from AStock.ASEvent import Worker
from AStock.ASSetting import settings, cons
from AStock.ASUtil import date_to_bar_format, date_from_bar_format, ASHttpParser
import json
from pymongo import UpdateOne


class ASPePercentageCrawler(Worker):

    def __init__(self):
        super(ASPePercentageCrawler, self).__init__()
        self._proxy = None
        self._handler = None
        self._code_mapping = None
        if settings.pe_percentage_source == cons.CrawlSource.EASTMONEY:
            self._url = cons.EASTMONEY_PE_PERCENTAGE_URL
            self._code_mapping = self._eastmoney_code
            self._handler = self._eastmoney_pe_percentage_handler

    @staticmethod
    def _eastmoney_code(code):
        return code + '01' if code[0] == '6' else code + '02'

    @staticmethod
    def _eastmoney_pe_percentage_handler(js, **kwargs):
        """
        解析响应的pe百分位
        :param js: json，待解析的响应json
        :return: dict，
            失败时，None
            成功时，{'code': '300000', 'pe30': 22, 'pe50': 30.5, 'pe70': 50.6}
        """
        try:
            code = kwargs['code'][:-2]
            if js and 'pe' in js and js['pe'] and js['pe'][0]:
                pe_percentage = js['pe'][0][0]
                pe_percentage = {
                    'code': code,
                    'pe30': pe_percentage['PE30'],
                    'pe50': pe_percentage['PE50'],
                    'pe70': pe_percentage['PE70']
                }

                return pe_percentage

        except KeyError as e:
            print('error parse eastmoney pe percentage: {}'.format(e))
            return None
        return None

    def run(self, event_data):
        """
        执行抓取pe百分位的任务
        :param event_data: dict，包括：
            event_type: pe_percentage 抓取pe百分位
            code: 300000 股票代码
        :return: dict，
            失败时，返回的字典为 {'error': 'error string'}
            成功时，{'code': '300000', 'pe30': 22, 'pe50': 30.5, 'pe70': 50.6}
        """
        try:
            event_type = event_data['event_type']
            code = event_data['code']
        except KeyError as e:
            return {'error': 'key error in event data, key: {}'.format(e)}

        if event_type not in ['pe_percentage']:
            return {'error': 'event type error: {}'.format(event_type)}

        if self._code_mapping:
            code = self._code_mapping(code)

        url = self._url.format(code=code)
        parser = ASHttpParser(url, cons.HEADER, self._proxy, content_type="json")
        res = parser.parse_json(
            json_handler=self._handler,
            charset=parser.charset,
            code=code
        )
        if res is None:
            return {'error': 'error crawl pe percentage, url: {}'.format(url)}
        return res


class ASPePercentageSaver(Worker):

    def __init__(self):
        super().__init__()

    def run(self, event_data):
        """
        执行保存pe百分位的任务
        :param event_data: dict，包括：
            event_type: pe_percentage 保存pe百分位
            code: str 股票代码
            pe30: float pe30百分位
            pe50: float pe50百分位
            pe70: float pe70百分位

        :return: dict，
            成功：{'succ': 'saved: 300001 pe percentage'}
            失败：{'fail': 'failed to save 300001 pe percentage'}
        """
        try:
            event_type = event_data['event_type']
            code = event_data['code']
            pe30 = event_data['pe30']
            pe50 = event_data['pe50']
            pe70 = event_data['pe70']
        except KeyError as e:
            return {'fail': 'key error in event data, key: {}'.format(e)}

        pe30 = round(float(pe30), 2) if pe30 else None
        pe50 = round(float(pe50), 2) if pe50 else None
        pe70 = round(float(pe70), 2) if pe70 else None

        if event_type not in ['pe_percentage']:
            return {'fail': 'event type error: {}'.format(event_type)}

        succ = 'saved {} pe percentage'.format(code)
        fail = 'failed to save {} pe percentage'.format(code)

        try:
            coll = settings.database.stock_valuation
            doc = {'code': code, 'pe30': pe30, 'pe50': pe50, 'pe70': pe70}
            coll.update_one({'code': code}, {'$set': doc}, upsert=True)
        except Exception as e:
            return {'fail': fail + '    ' + str(e)}

        return {'succ': succ}
